/**
 * All Rights Reserved , Copyright (C) 2020 , 青岛鼎信通讯股份有限公司
 * <p>
 * MpmProjectAppointmentService
 * 项目任命
 * <p>
 * 修改纪录
 * 2020-12-28 版本：1.0 lanjianwei 创建。
 *
 * @version 版本：1.0
 * @author 作者：lanjianwei
 * 创建日期：2020-12-28
 */
package com.topscomm.mpm.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.sun.mail.util.MailSSLSocketFactory;
import com.topscomm.basic.BasicEntity;
import com.topscomm.basic.exception.BusinessException;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.basic.util.PrimaryKeyUtil;
import com.topscomm.basic.util.SQLAdapter;
import com.topscomm.cbo.pojo.*;
import com.topscomm.cbo.service.*;
import com.topscomm.cbo.service.impl.CboDeptService;
import com.topscomm.cbo.service.impl.CboUserService;
import com.topscomm.main.hessian.IBaseChangeLogService;
import com.topscomm.main.hessian.IMmsDeptExtraInfoService;
import com.topscomm.message.mail.MailMessageEntity;
import com.topscomm.mpm.MpmSystemConst;
import com.topscomm.mpm.pojo.*;
import com.topscomm.mpm.service.IMpmProjectAppointmentService;
import com.topscomm.mpm.service.IMpmProjectService;
import com.topscomm.mpm.service.IMpmProjectTeamService;
import com.topscomm.mpm.service.IMpmProjectTeamTypeService;
import com.topscomm.mpm.service.impl.auto.MpmProjectAppointmentServiceAuto;
import com.topscomm.mpm.utils.ConvertTimeUtil;
import com.topscomm.mpm.utils.GenerateAppointmentTemplateUtil;
import com.topscomm.mpm.utils.PdfToImageUtil;
import com.topscomm.pub.util.*;
import com.topscomm.pub.vo.ResponseResult;
import com.topscomm.tap.TapEntity;
import com.topscomm.tap.TapService;
import com.topscomm.tap.common.*;
import lombok.SneakyThrows;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.io.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.unzip.UnzipUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.annotation.Resource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service(value = "mpmProjectAppointmentService")
@Scope(value = "singleton")
public class MpmProjectAppointmentService extends MpmProjectAppointmentServiceAuto implements IMpmProjectAppointmentService {
    private static final Logger logger = LoggerFactory.getLogger(MpmProjectAppointmentService.class);

    FlowDatacodeCache flowDatacodeCache = new FlowDatacodeCache();
    protected List<Map<String, Object>> flowidList = new ArrayList();
    @Resource(name = "mpmProjectTeamService")
    private IMpmProjectTeamService mpmProjectTeamService;

    @Autowired
    private IMpmProjectTeamTypeService mpmProjectTeamTypeService;

    @Autowired
    private ICboAttachmentService cboAttachmentService;

    @Autowired
    private ICboAttachmentTypeService cboAttachmentTypeService;

    @Autowired
    private IMpmProjectService mpmProjectService;

    @Autowired
    private ICboUserService cboUserService;

    @Autowired
    private ICboDeptService cboDeptService;
    @Autowired
    private ICboMessageAppService cboMessageAppService;
    @Autowired
    private ICboMessageSysService cboMessageSysService;
    @Autowired
    private MpmWorkingCalendarService mpmWorkingCalendarService;
    @Autowired
    private IBaseChangeLogService baseChangeLogService;
    @Autowired
    private IMmsDeptExtraInfoService iMmsDeptExtraInfoService;

    private static final String INVALID_ADDRESS_MESSAGE = "Invalid Addresses";

    private static Map<String, String> levelMap = new HashMap<>();

    static {
		levelMap.put("0", "A");
		levelMap.put("1", "B");
		levelMap.put("2", "C");
		levelMap.put("3", "D");
	}

    /**
     * @author: lanjianwei
     * @date: 2020-12-28
     * @param entity
     * @throws ServiceException
     * @description:单号生成
     * @modify:
     */
    @Override
    protected void beforeInsert(BasicEntity entity) {
        super.beforeInsert(entity);
        if (entity.getId() <= 0) {// 赋值Id和单号
            long[] arrayId = PrimaryKeyUtil.GeneIDs(entity.getTableName(), 1);
            entity.setId(arrayId[0]);
            String docNo = String.valueOf(arrayId[0]);
            docNo = docNo.substring(0, 6) + docNo.substring(9);
            entity.setValue(MpmProjectAppointmentEntity.FieldDocno, docNo);

        }
        // 判断是否是第一次任命
        MpmProjectAppointmentEntity appointmentEntity = (MpmProjectAppointmentEntity) entity;
        String projectCode = appointmentEntity.getProjectcode();
        List<Map<String, Object>> maps = this.selectExecute(" select count(id) as count from MpmProjectAppointment where projectcode = '" + projectCode + "'");
        int count = ConvertUtil.convertToInt(maps.get(0).get("count"));
        if (count == 0) {
            appointmentEntity.setSyspush("1");
        }

    }

    /**
     * @Description: 生成任命书编号
     * @Author: mengmeng
     * @Date: 2021/8/18 17:02
     * @Version: 1.0
     */
    public String generateAppointNumber(String projectCode) {
        // 获取项目等级
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" {0} = '{1}' ", MpmProjectEntity.FieldProjectcode, projectCode);
        List<MpmProjectEntity> mpmProjectEntities = mpmProjectService.queryByWhere(sql.toString());
        if (CollectionUtils.isEmpty(mpmProjectEntities)) {
            return "";
        }
        String projectLevel = mpmProjectEntities.get(0).getProjectlevel();
        //赋值任命书编号
        sql.clear();
        SimpleDateFormat sdFormat = new SimpleDateFormat("yyyyMM");
        String dateCode = sdFormat.format(new Date());
        String substring = dateCode.substring(0, 4);
        String month = dateCode.substring(4);
        String flowCode = "";
		boolean isABLevel = "0".equals(projectLevel) || "1".equals(projectLevel);
		if (isABLevel) {
		    // A、B 级项目
            sql.appendSingle("select APPOINTMENTNUMBER from MPMPROJECTAPPOINTMENT a left join MPMPROJECT b on a.projectcode = b.projectcode where b.projectlevel in ({0}) and a.APPOINTMENTNUMBER like '%{1}%' order by a.CREATEON DESC ", "'0','1'", substring);
            // 按照创建日期倒序取A、B级项目的任命书编号
            List<Map<String, Object>> appointmentnumberlist = this.selectExecute(sql.toString());
            if (appointmentnumberlist.size() != 0) {
                // 取当月任命书中编号最大的编号
                String lastMaxIndex = "0";
                for (Map<String, Object> temp : appointmentnumberlist) {
                    String appointmentNumber = ConvertUtil.convertToString(temp.get("appointmentnumber"));
                    // AB级的项目任命书编号为12位,并且是当月的
                    if (!StringUtil.isEmpty(appointmentNumber) && appointmentNumber.length() == 12 && month.equals(getMonthOfAppointmentNumber(appointmentNumber, true))) {
                        //
                        String indexOfAppointmentNumber = getIndexOfAppointmentNumber(appointmentNumber, true);
                        lastMaxIndex = ConvertUtil.convertToInt(lastMaxIndex) < ConvertUtil.convertToInt(indexOfAppointmentNumber) ? indexOfAppointmentNumber : lastMaxIndex;
                    }
                }
                if ("0".equals(lastMaxIndex)) {
                    // 没有当月的数据
                    flowCode = "001";
                } else {
                    // 当月最大顺序号加一
                    DecimalFormat decimalFormat = new DecimalFormat("000");
                    int i = Integer.parseInt(lastMaxIndex) + 1;
                    flowCode = decimalFormat.format(i);
                }
            } else {
                // 如果为空，则当前任命为当月生成的第一份任命书
                flowCode = "001";
            }
            flowCode = "[" + substring + "]" + month + flowCode + "号";
            return flowCode;
        } else {
		    // C、D 级项目
            sql.appendSingle("select APPOINTMENTNUMBER from MPMPROJECTAPPOINTMENT a left join MPMPROJECT b on a.projectcode = b.projectcode where b.projectlevel in ({0}) and a.APPOINTMENTNUMBER like '%{1}%' order by a.CREATEON DESC ", "'2','3'", substring);
            List<Map<String, Object>> appointmentnumberlist = this.selectExecute(sql.toString());
            if (appointmentnumberlist.size() != 0) {
                String lastMaxIndex = "0";
                for (Map<String, Object> temp : appointmentnumberlist) {
                    String appointmentNumber = ConvertUtil.convertToString(temp.get("appointmentnumber"));
                    // AB级的项目任命书编号为12位,并且是当月的
                    if (!StringUtil.isEmpty(appointmentNumber) && appointmentNumber.length() == 13 && month.equals(getMonthOfAppointmentNumber(appointmentNumber, false))) {
                        //
                        String indexOfAppointmentNumber = getIndexOfAppointmentNumber(appointmentNumber, false);
                        lastMaxIndex = ConvertUtil.convertToInt(lastMaxIndex) < ConvertUtil.convertToInt(indexOfAppointmentNumber) ? indexOfAppointmentNumber : lastMaxIndex;
                    }
                }
                if ("0".equals(lastMaxIndex)) {
                    flowCode = "001";
                } else {
                    // 当月最大顺序号加一
                    DecimalFormat decimalFormat = new DecimalFormat("000");
                    int i = Integer.parseInt(lastMaxIndex) + 1;
                    flowCode = decimalFormat.format(i);
                }
            } else {
                flowCode = "001";
            }
            flowCode = "[" + substring + "]" + levelMap.get(projectLevel) + month + flowCode + "号";
            return flowCode;
        }
    }

    /**
    * @Description:    获取任命书编号的顺序号
    * @Author:         mengmeng
    * @Date:           2021/10/22 17:44
    * @Version:        1.0
    */
    private String getIndexOfAppointmentNumber(String appointmentNumber, boolean whetherABLevel) {
        if (whetherABLevel) {
            return appointmentNumber.substring(8, 11);
        }
        return appointmentNumber.substring(9, 12);
    }

    /**
     * @Description:    获取任命书编号的月份
     * @Author:         mengmeng
     * @Date:           2021/10/22 17:44
     * @Version:        1.0
     */
    private String getMonthOfAppointmentNumber(String appointmentNumber, boolean whetherABLevel) {
        if (whetherABLevel) {
            return appointmentNumber.substring(6, 8);
        }
        return appointmentNumber.substring(7, 9);
    }

    /**
     * @Title: beforeSubmit
     * @description: 插入流程，更细子表数据
     * @param entity
     * @param sessionUserBean
     * @author: lanjianwei
     * @date: 2021年1月7日上午9:55:15
     * @modify:
     */
    @SneakyThrows
    @Override
    protected void beforeSubmit(TapEntity entity, SessionUserBean sessionUserBean) {
        super.beforeSubmit(entity, sessionUserBean);
        MpmProjectAppointmentEntity mpmProjectAppointmentEntity = (MpmProjectAppointmentEntity) entity;
        this.flowidList = flowDatacodeCache.getApprovalFlowListMap("ApprovalFlow_MpmProjectAppointment",
                mpmProjectAppointmentEntity.getApplyusercode(), "sortcode");
        if (flowidList.size() > 0) {// 赋值审批流程id
            mpmProjectAppointmentEntity.setFlowid(ConvertUtil.convertToLong(flowidList.get(0).get("id")));
        } else {
            throw new ServiceException("没有匹配的审批流，请联系管理员！");
        }
        //子表行状态更新
        long id = mpmProjectAppointmentEntity.getId();
        StringBufferProxy whersql = new StringBufferProxy();
        whersql.appendLineSingle("appointmentid = '{0}'", id);
        List<MpmProjectTeamEntity> mpmProjectTeamEntities = mpmProjectTeamService.queryByWhere(whersql.toString());
        for (MpmProjectTeamEntity mpmProjectTeamEntity : mpmProjectTeamEntities) {
            mpmProjectTeamEntity.setState(1);
            mpmProjectTeamService.updateEntity(mpmProjectTeamEntity);
        }
        // 更新主表提醒时间，不再提醒
        String projectCode = mpmProjectAppointmentEntity.getProjectcode();
        List<MpmProjectEntity> projectList = mpmProjectService.queryByWhere(" projectcode  = '" + projectCode + "'");
        if (!CollectionUtils.isEmpty(projectList)) {
            MpmProjectEntity project = projectList.get(0);
            project.setReminddate(null);
            mpmProjectService.updateEntity(project);
        }
        // 任命变更存储basechangelog表变更字段信息
        String sysPush = mpmProjectAppointmentEntity.getSyspush();
        if (StringUtil.isEmpty(sysPush)) {
            this.approvalSaveAppointmentLog(mpmProjectAppointmentEntity);
        }
    }

    @Override
    @Transactional
    protected void afterInsert(BasicEntity entity) throws ServiceException {
        MpmProjectAppointmentEntity appointmentEntity = (MpmProjectAppointmentEntity) entity;
        String projectCode = appointmentEntity.getProjectcode();
        long appointId = appointmentEntity.getId();
        String sysPush = appointmentEntity.getSyspush();

        if (!StringUtil.isEmpty(sysPush) && sysPush.equals("1")) {
            // 首次任命，如果客户为省级且采购模式为招标，生成三个组（业务、标前引导、标书），否则生成项目核心组
            if (isGenGroup(projectCode)) {
                mpmProjectTeamTypeService.insertBatch(mpmProjectTeamTypeService.insertGenGroup(projectCode, appointId));
            } else {
                mpmProjectTeamTypeService.insertTeamType(projectCode, appointId);
            }
        } else {
            // 二次任命，复制上次的任命成员
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendSingle(" projectcode = '{0}' ", projectCode);
            sql.appendSingle(" order by createon desc ");
            // 查询最近上一次的任命书
            List<MpmProjectAppointmentEntity> list = this.queryByWhere(sql.toString());
            if (CollectionUtils.isEmpty(list) || list.size() == 1) {
                // 如果为空，则应该是首次任命
                if (isGenGroup(projectCode)) {
                    mpmProjectTeamTypeService.insertBatch(mpmProjectTeamTypeService.insertGenGroup(projectCode, appointId));
                } else {
                    mpmProjectTeamTypeService.insertTeamType(projectCode, appointId);
                }
                return;
            }
            MpmProjectAppointmentEntity lastAppointment = list.get(1);
            // 查询上次任命的人员和项目组类型
            List<MpmProjectTeamEntity> projectTeamDoList = mpmProjectTeamService.queryByAppointmentId(ConvertUtil.convertToString(lastAppointment.getId()));
            Map<Long, List<MpmProjectTeamEntity>> teamIdMap = projectTeamDoList.stream().collect(Collectors.groupingBy(MpmProjectTeamEntity::getTeamid));
            List<MpmProjectTeamTypeEntity> appointmentHistoryList = mpmProjectTeamTypeService.queryByAppointmentId(ConvertUtil.convertToString(lastAppointment.getId()));
            if (CollectionUtils.isEmpty(appointmentHistoryList)) {
                // 历史数据，暂不带出项目组和团队成员
                if (isGenGroup(projectCode)) {
                    mpmProjectTeamTypeService.insertBatch(mpmProjectTeamTypeService.insertGenGroup(projectCode, appointId));
                } else {
                    mpmProjectTeamTypeService.insertTeamType(projectCode, appointId);
                }
                return;
            }
            // 剔除撤销的工作组
            appointmentHistoryList = appointmentHistoryList.stream().filter(item -> MpmSystemConst.MpmTeamTypeAppointment.appointment.equals(item.getAppointmenttype())).collect(Collectors.toList());
            // 复制上次任命的团队和名称
            List<BasicEntity> newTeamTypeList = new ArrayList<>();
            List<BasicEntity> newTeamList = new ArrayList<>();
            MpmProjectTeamEntity newTeamDo = null;
            for (MpmProjectTeamTypeEntity teamType : appointmentHistoryList) {
                MpmProjectTeamTypeEntity teamTypeDo = copyTeamTypeDo(appointId, teamType);
                newTeamTypeList.add(teamTypeDo);
                List<MpmProjectTeamEntity> teamList = teamIdMap.get(teamType.getId());
                if (CollectionUtils.isEmpty(teamList)) {
                    continue;
                }
                for (MpmProjectTeamEntity teamDo : teamList) {
                    if ("2".equals(teamDo.getAppointmenttype())) {
                        // 撤销任命
                        continue;
                    }
                    newTeamDo = teamDo;
                    newTeamDo.setCopysourceid(newTeamDo.getId());
                    newTeamDo.setId(0L);
                    newTeamDo.setState(0);
                    newTeamDo.setTeamid(teamTypeDo.getId());
                    newTeamDo.setAppointmentid(appointId);
                    newTeamDo.setCandelete(MpmSystemConst.MPM_TEAM_CAN_NOT_DELETE);
                    newTeamList.add(newTeamDo);
                }
            }
            // 判断项目是否为省级招标项目,代码注释原因（经营管理部要求任命变更的项目组从上一次带出即可，不需要判断省级招标A级项目）
//            if (isGenGroup(projectCode)) {
//                // 如果省级招标项目中没有3个模板任命组，则新增，有则不进行操作
//                boolean needTemplate = true;
//                for (BasicEntity basicEntity : newTeamTypeList) {
//                    if (ConvertUtil.convertToInt(basicEntity.getValue("grouptype")) > 0) {
//                        needTemplate = false;
//                    }
//                }
//                if (needTemplate) {
//                    newTeamTypeList.addAll(mpmProjectTeamTypeService.insertGenGroup(projectCode, appointId));
//                }
//                // 剔除项目核心组及组内成员
//                newTeamTypeList = newTeamTypeList.stream().filter(item -> !MpmSystemConst.ProjectCoreTeamType.equals(ConvertUtil.convertToString(item.getValue("teamname")))).collect(Collectors.toList());
//                newTeamList = newTeamList.stream().filter(item -> !MpmSystemConst.ProjectCoreTeamType.equals(ConvertUtil.convertToString(item.getValue("workgroup")))).collect(Collectors.toList());
//            }
            mpmProjectTeamTypeService.insertBatch(newTeamTypeList);
            mpmProjectTeamService.insertBatch(newTeamList);
        }
    }

    /**
    * @Description:    复制团队类型
    * @Author:         mengmeng
    * @Date:           2021/8/30 9:21
    * @Version:        1.0
    */
    private MpmProjectTeamTypeEntity copyTeamTypeDo(long appointId, MpmProjectTeamTypeEntity teamType) {
        MpmProjectTeamTypeEntity newTeamTypeDo = new MpmProjectTeamTypeEntity();
        BeanUtils.copyProperties(teamType, newTeamTypeDo);
        long[] arrayId = PrimaryKeyUtil.GeneIDsFromCache(teamType.getTableName(), 1);
        newTeamTypeDo.setCopysourceid(newTeamTypeDo.getId());
        newTeamTypeDo.setId(arrayId[0]);
        newTeamTypeDo.setAppointmentid(appointId);
        newTeamTypeDo.setSortCode(teamType.getSortcode());
        newTeamTypeDo.setDescription(ConvertUtil.convertToString(teamType.getId()));
        return newTeamTypeDo;
    }

    /**
     * @Description: 生成任命书
     * @Author: mengmeng
     * @Date: 2021/8/10 15:57
     * @Version: 1.0
     */
    @Override
    @Transactional
    public void generateAppointment(Map<String, Object> param) throws Exception {
        String appointmentId = ConvertUtil.convertToString(param.get("appointmentid"));
        // 前台传入参数没有项目等级时
        if (!param.containsKey("projectlevel")) {
            MpmProjectAppointmentEntity mpmProjectAppointmentEntity = this.queryById(appointmentId);
            if (!mpmProjectAppointmentEntity.getProjectcode().isEmpty()) {
                MpmProjectEntity mpmProjectEntity = mpmProjectService.queryObjectByWhere("projectcode = '" + mpmProjectAppointmentEntity.getProjectcode() + "'");
                param.put("projectlevel", mpmProjectEntity.getProjectlevel());
            }
        }
        Boolean ifBLevel = "1".equals(param.get("projectlevel"));
        Boolean ifCLevel = MpmSystemConst.ProjectLevel.C.equals(param.get("projectlevel"));
        deleteAppointment(appointmentId);
        Date now = new Date();
        param.put("nowdate", new SimpleDateFormat("yyyy-M-dd").format(now));
        param.put("nowdateup", ConvertTimeUtil.dataToUpper3(new SimpleDateFormat("yyyy-MM-dd").format(now)));
        String tempZipDirectoryName = null;
        String property = System.getProperties().getProperty("file.separator");
        String projectName = ConvertUtil.convertToString(param.get("projectname"));
        projectName = projectName.endsWith("项目") ? projectName : projectName + "项目";
        String distFileName = projectName + "任命书";
        // 删除文件名中不允许包含的字符，防止报错
        String[] split = MpmSystemConst.generateAppointmentPrevent.split(",");
        for(String str : split) {
            distFileName = distFileName.replaceAll(str, "");
        }
        try {
            // 临时目录，用于解压缩文件
            String uuid = UUID.randomUUID().toString();
            tempZipDirectoryName = BaseUtil.getProjectPath() + "zip" + property + uuid;
            File tempZipDirectory = new File(tempZipDirectoryName);
            if (!tempZipDirectory.exists() && !tempZipDirectory.isDirectory()) {
                tempZipDirectory.mkdirs();
            }
            // 下载模板文件
            downloadTemplate(tempZipDirectoryName, ifBLevel, ifCLevel);
            // 转换模板文件

            GenerateAppointmentTemplateUtil.readWordFile(param, tempZipDirectoryName + property + "项目任命书模板.docx", tempZipDirectoryName, distFileName);
            // 上传任命书
            uploadAppointment(appointmentId, new File(tempZipDirectoryName + property + distFileName + ".docx"));
        } catch (Exception e) {
            throw new ServiceException(e);
        } finally {
            // 删除压缩文件
            FileUtil.deleteFile(tempZipDirectoryName + property + "项目任命书模板.docx");
            FileUtil.deleteFile(tempZipDirectoryName + property + distFileName + "任命书");
            // 删除临时目录
            FileUtil.deleteDirectory(tempZipDirectoryName, true);
        }
    }

    /**
     * @Description: 转pdf后下载模板文件
     * @Author: mengmeng
     * @Date: 2021/8/16 14:14
     * @Version: 1.0
     */
    @Override
    public Map<String, Object> executeDownload(Map<String, Object> paraMap) {
        Map<String, Object> resultMap = new HashMap<String, Object>();
        try {
            // 附件对象
            StringBufferProxy sqlWhere = new StringBufferProxy();
            if (paraMap.containsKey("attachmentId")) {
                String attachmentId = ConvertUtil.convertToString(paraMap.get("attachmentId"));
                sqlWhere.appendLineSingle(" id={0}", attachmentId);
            } else {
                sqlWhere.appendLineSingle(" 1=1 ");
                if (paraMap.containsKey("sourcetype"))
                    sqlWhere.appendLineSingle(" and sourcetype='{0}'",
                            ConvertUtil.convertToString(paraMap.get("sourcetype")));
                if (paraMap.containsKey("sourceid"))
                    sqlWhere.appendLineSingle(" and sourceid='{0}'",
                            ConvertUtil.convertToString(paraMap.get("sourceid")));
            }
            Map<String, Object> queryMap = new HashMap<String, Object>();
            queryMap.put("whereSql", sqlWhere.toString());
            CboAttachmentEntity attachment = cboAttachmentService.getByte(queryMap);
            resultMap.put("attFileName", attachment.getDisplayname());
            // 存储配置
            CboAttachmentTypeEntity attachmentType = cboAttachmentTypeService
                    .queryById(ConvertUtil.convertToString(attachment.getAttachmenttypeid()));
            if (attachmentType == null) {
                throw new ServiceException("没有设置正确的配置参数！");
            }
            if (attachmentType.getStoretype().equals(TapSystemConst.TapAttachmentStoreType.FTP)) {
                downloadFtp(resultMap, paraMap, attachment, attachmentType);
            }
        } catch (Exception e) {
            throw new ServiceException(e);
        }
        return resultMap;
    }

    /**
    * @Description:    返回true不需要发送邮件
    * @Author:         mengmeng
    * @Date:           2021/8/24 15:55
    * @Version:        1.0
    */
    public boolean judgeSendTime(String createOnStr, Date createOnDate) {
        boolean strEmpty = StringUtil.isEmpty(createOnStr);
        boolean dateEmpty = createOnDate == null;
        if (strEmpty && dateEmpty) {
            return false;
        }
        String sendEmailTime = ParameterCache.getValue("sendEmailTime");
        Date parse = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date createOnTime = null;
        try {
            parse = simpleDateFormat.parse(sendEmailTime);
            if (!strEmpty) {
                createOnTime = simpleDateFormat.parse(createOnStr);
                return createOnTime.before(parse);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return createOnDate.before(parse);
    }

    @Override
    @Transactional
    public void remindTimeOutProject() {
        // 获取到时间需要提醒的项目列表
        StringBufferProxy sql  = new StringBufferProxy();
        sql.appendSingle(" state =  9 ");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = simpleDateFormat.format(new Date());
        String s = SQLAdapter.toDateLong(format);
        sql.appendSingle(" and reminddate is not null and reminddate  <= {0} ", s);
        List<MpmProjectEntity> projectList = mpmProjectService.queryByWhere(sql.toString());
        if (CollectionUtils.isEmpty(projectList)) {
            return;
        }
        // 判断该项目是否没有项目任命，或者只有一条立项待审批的任命
        String projectCodeStr = projectList.stream().map(MpmProjectEntity::getProjectcode).map(item -> "'" + item + "'").collect(Collectors.joining(","));
        sql.clear();
        sql.appendSingle(" {0} in ({1}) and state in (1, 2, 9)", MpmProjectAppointmentEntity.FieldProjectcode, projectCodeStr);
        List<MpmProjectAppointmentEntity> appointmentList = this.queryByWhere(sql.toString());
        if (CollectionUtils.isEmpty(appointmentList)) {
            // 表示 projectCodeStr中的所有项目都没有正在审批或审批结束的任命，都需要提醒
            insertMessageAppFromTask(projectList);
            return;
        }
        Map<String, List<MpmProjectAppointmentEntity>> projectCodeToAppointmentMap = appointmentList.stream().collect(Collectors.groupingBy(MpmProjectAppointmentEntity::getProjectcode));
        List<MpmProjectEntity> resultProjectList = new ArrayList<>();
        for (MpmProjectEntity project : projectList) {
            String projectCode = project.getProjectcode();
            if (!projectCodeToAppointmentMap.containsKey(projectCode)) {
                // 不包含该projectCode主键，说明没有该projectCode为主键的任命书
                resultProjectList.add(project);
            }
        }
        insertMessageAppFromTask(resultProjectList);
    }

    /**
    * @Description:    APP消息提醒
    * @Author:         mengmeng
    * @Date:           2021/8/31 14:14
    * @Version:        1.0
    */
    private void insertMessageAppFromTask(List<MpmProjectEntity> projectList) {
        if (CollectionUtils.isEmpty(projectList)) {
            return;
        }
        String remindAfterRemind = ParameterCache.getValue("remindAfterRemind", "1");
        String codeStr = projectList.stream().map(MpmProjectEntity::getProjectmanagercode).map(item -> "'" + item + "'").collect(Collectors.joining(","));
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" code in ({0}) ", codeStr);
        List<CboUserEntity> userList = cboUserService.queryByWhere(sql.toString());
        Map<String, Long> codeToIdMap = userList.stream().collect(Collectors.toMap(CboUserEntity::getCode, CboUserEntity::getId, (v1, v2) -> v1));
        List<Map<String, Object>> cboMessageAppMapList = new ArrayList<>();
        List<BasicEntity> cboMessageSysEntityList = new ArrayList<>();
        String subjectStr = "任命";
        String content = "已处于任命阶段，请前往销售管理系统任命！";
        String projectName = "";
        Calendar calendar = Calendar.getInstance();
        List<BasicEntity> mpmProjectList = new ArrayList<>();
        Date now = new Date();
        for (MpmProjectEntity project : projectList) {
            projectName = project.getProjectname();
            projectName = projectName.endsWith("项目") ? projectName : projectName + "项目";
            // MessageApp消息发送
            Map<String, Object> cboMessageAppMap = new HashMap<>();
            cboMessageAppMap.put(CboMessageAppEntity.FieldContent, projectName + content);
            cboMessageAppMap.put(CboMessageAppEntity.FieldSourcetype, MpmProjectEntity.tableName);
            cboMessageAppMap.put(CboMessageAppEntity.FieldSourceid, project.getId());
            String projectManagerCode = project.getProjectmanagercode();
            cboMessageAppMap.put(CboMessageAppEntity.FieldReceiverid, codeToIdMap.get(projectManagerCode));
            cboMessageAppMap.put("usercode", projectManagerCode);
            cboMessageAppMap.put(CboMessageAppEntity.FieldSendtype, 0);
            cboMessageAppMap.put(CboMessageAppEntity.FieldExtendfield1, projectName + subjectStr);// 从task表改
            cboMessageAppMapList.add(cboMessageAppMap);
            // MessageSys消息发送
            CboMessageSysEntity cboMessageSysEntity = new CboMessageSysEntity();
            cboMessageSysEntity.setContent(projectName + content);
            cboMessageSysEntity.setSourcetype(MpmProjectEntity.tableName);
            cboMessageSysEntity.setSourceid(project.getId());
            cboMessageSysEntity.setReceivercode(projectManagerCode);
            cboMessageSysEntity.setReceivername(project.getProjectmanager());
            cboMessageSysEntity.setSubject(projectName + subjectStr);
            cboMessageSysEntityList.add(cboMessageSysEntity);
            // 更新提醒时间
            calendar.setTime(now);
            calendar.add(Calendar.DAY_OF_MONTH, ConvertUtil.convertToInt(remindAfterRemind));
            project.setReminddate(calendar.getTime());
            mpmProjectList.add(project);
        }
        // 每50条数据插一次，防止oa hessian超时
        int baseRemindTaskEntityAppRemindListSize = projectList.size();
        int lastIndex = 0;
        for (int i = 1; i <= baseRemindTaskEntityAppRemindListSize; i++) {
            if (i % 50 == 0 || i == (baseRemindTaskEntityAppRemindListSize)) {
                try {
                    this.cboMessageAppService.insertList(cboMessageAppMapList.subList(lastIndex, i));
                    this.cboMessageSysService.insertBatch(cboMessageSysEntityList.subList(lastIndex, i));
                } catch (Exception e) {
                }
                lastIndex = i;
            }
        }
        mpmProjectService.updateBatch(mpmProjectList);
    }


    /**
     * @Description: 转pdf发送邮件
     * @Author: mengmeng
     * @Date: 2021/8/16 14:15
     * @Version: 1.0
     */
    public void sendMessage(String appointId) {
        // 获取任命书对象
        Map<String, Object> appointDoMap = this.queryMapById(appointId);
        if (null == appointDoMap || appointDoMap.isEmpty()) {
            return;
        }
        String createOn = ConvertUtil.convertToString(appointDoMap.get(MpmProjectAppointmentEntity.FieldCreateon));

        // 判断是否是系统参数时间之前的任命书，不需要发送，为了处理历史数据
        if (judgeSendTime(createOn, null)) {
            return;
        }
        // 获取项目等级
        String projectCode = ConvertUtil.convertToString(appointDoMap.get(MpmProjectAppointmentEntity.FieldProjectcode));
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" {0} = '{1}' ", MpmProjectEntity.FieldProjectcode, projectCode);
        List<MpmProjectEntity> mpmProjectEntities = mpmProjectService.queryByWhere(sql.toString());
        if (CollectionUtils.isEmpty(mpmProjectEntities)) {
            return;
        }
        String projectLevel = mpmProjectEntities.get(0).getProjectlevel();
        // A、B发送邮件，C、D级不发送邮件
        if (StringUtil.isEmpty(projectLevel) || (!"0".equals(projectLevel) && !"1".equals(projectLevel))) {
            return;
        }
        // 判断是一次任命还是二次任命
        String sysPush = ConvertUtil.convertToString(appointDoMap.get(MpmProjectAppointmentEntity.FieldSyspush));
        String copyMailTo = "";

        List<MpmProjectTeamEntity> projectTeamDoList = mpmProjectTeamService.queryByAppointmentId(appointId);
        // 需要发送邮件的人员
        List<String> userCodeList = getStrings(appointDoMap, projectTeamDoList);
        if (CollectionUtils.isEmpty(userCodeList)) {
            return;
        }
        // 获取任务对应一级部门长
        MpmProjectEntity mpmTargetProjectEntity = mpmProjectEntities.get(0);
        String provincemanagercode = "";
        String provincemanagername = "";
        if (!mpmTargetProjectEntity.getDeptcommoncode().isEmpty()) {
            List<Map<String, Object>> list = mpmProjectService.
                    queryMapByWhere("DEPTCOMMONCODE = " + mpmTargetProjectEntity.getDeptcommoncode() + "", "queryProvinceCEO");
             provincemanagercode =  ConvertUtil.convertToString(list.get(0).get("PROVINCEMANAGERCODE"));
             provincemanagername =  ConvertUtil.convertToString(list.get(0).get("PROVINCEMANAGERNAME"));

        }
        String userCodeStr = "";
        String comPare = "'" + provincemanagercode + "'";
        // 判断任务级别
        if (MpmSystemConst.ProjectLevel.A.equals(projectLevel)) {
            userCodeStr = userCodeList.stream().distinct().map(item -> "'" + item + "'").collect(Collectors.joining(","));
            if (!provincemanagercode.isEmpty() && !userCodeStr.isEmpty() && !userCodeStr.contains(comPare)) {
                userCodeStr = userCodeStr + ",'" + provincemanagercode + "'";
            }else if(!provincemanagercode.isEmpty() && userCodeStr.isEmpty()) {
                userCodeStr = provincemanagercode;
                // 当前项目组成员包括省总
            }else if(!provincemanagercode.isEmpty() && !userCodeStr.isEmpty() && userCodeStr.contains(comPare)){

            }
            copyMailTo = ParameterCache.getValue("MpmEMTForMail");

        } else if (MpmSystemConst.ProjectLevel.B.equals(projectLevel) ){
            userCodeStr = userCodeList.stream().distinct().map(item -> "'" + item + "'").collect(Collectors.joining(","));
            if (!provincemanagercode.isEmpty()) {
                CboUserEntity provinceManager = cboUserService.queryObjectByWhere("enabled = 1 and code = " + "'" + provincemanagercode + "'");
                copyMailTo = provinceManager.getEmail() ;
            }
        } else {
        }
        // copyMailTo = "houyuhang@topscomm.com";

//        String mpmMailToUserCode = ParameterCache.getValue("MpmMailToUserCode");
//        Set<String> paramUserCode = StringUtil.isEmpty(mpmMailToUserCode) ? null : Arrays.stream(mpmMailToUserCode.split(",")).collect(Collectors.toSet());
//        String userCodeStr = "";
//        if (!CollectionUtils.isEmpty(paramUserCode)) {
//            userCodeStr = userCodeList.stream().distinct().filter(item -> paramUserCode.contains(item)).map(item -> "'" + item + "'").collect(Collectors.joining(","));
//        }
//        else {
//            userCodeStr = userCodeList.stream().distinct().map(item -> "'" + item + "'").collect(Collectors.joining(","));
//        }
        if (StringUtil.isEmpty(userCodeStr)) {
            // 当发送邮件的人员为空时，默认发送给指定人员
            String defaultToUserCode = ParameterCache.getValue("MpmMailDefaultToUserCode");
            if (StringUtil.isEmpty(defaultToUserCode)) {
                return;
            }
            userCodeStr = defaultToUserCode;
        }
        List<CboUserEntity> cboUserDoList = cboUserService.queryByWhere(" code in (" + userCodeStr + ")");
        String mailTo = cboUserDoList.stream().map(CboUserEntity::getEmail).collect(Collectors.joining(","));
        // mailTo = "wuyuyang@topscomm.com";
        // 获取任命书编号
        String appointNum = ConvertUtil.convertToString(appointDoMap.get(MpmProjectAppointmentEntity.FieldAppointmentnumber));
        if (appointNum.contains("[") && appointNum.contains("]")) {
            appointNum = appointNum.replace("[", "【").replace("]", "】");
        }
        String projectName = ConvertUtil.convertToString(appointDoMap.get(MpmProjectAppointmentEntity.FieldProjectname));
        String emailTitle = "";
        String fileName = "";
        if (!StringUtil.isEmpty(sysPush) && "1".equals(sysPush)) {
            // 一次任命
//            copyMailTo = ParameterCache.getValue("MpmFirstAppointMail");
            emailTitle = "鼎信销售项目组任命" + appointNum + "-[" + projectName + "]" + "任命通知";
            fileName = projectName + "任命书";
        } else {
            // 二次任命
//            copyMailTo = ParameterCache.getValue("MpmSecondAppointMail");
            emailTitle = "鼎信销售项目组任命" + appointNum + "-[" + projectName + "]" + "任命变更通知";
            fileName = projectName + "任命书-变更";
        }

        // 删除文件名中不允许包含的字符，防止报错
        String[] split = MpmSystemConst.generateAppointmentPrevent.split(",");
        for(String str : split) {
            fileName = fileName.replaceAll(str, "");
        }
        // 获取附件对象
        StringBufferProxy sqlWhere = new StringBufferProxy();
        sqlWhere.appendLineSingle(" sourcetype='{0}'", "MpmProjectAppointmentGenerate");
        sqlWhere.appendLineSingle(" and sourceid='{0}'", appointId);
        List<CboAttachmentEntity> attachmentEntityList = cboAttachmentService.queryByWhere(sqlWhere.toString());
        if (CollectionUtils.isEmpty(attachmentEntityList)) {
            return;
        }
        CboAttachmentEntity attachment = attachmentEntityList.get(0);
        // 存储配置
        CboAttachmentTypeEntity attachmentType = cboAttachmentTypeService
                .queryById(ConvertUtil.convertToString(attachment.getAttachmenttypeid()));
        String mailAttachmentPath = null;
        String currentNanoTime = ConvertUtil.convertToString(System.nanoTime());
        String tempZipDirectoryName = System.getProperty("user.dir").replace("bin", "webapps") + "/mailZip/"
                + currentNanoTime + "/";
        // 获取密送地址
        String secretMailTo = ParameterCache.getValue("MpmAppointSecretMail");
        // 如果不是正式环境，修改发送、抄送、密送人员为系统管理人员
        if (!ParameterCache.getBooleanValue("MpmSendEmailFlag",false)) {
            mailTo = ParameterCache.getValue("MpmMailTempCode");
            copyMailTo = ParameterCache.getValue("MpmMailTempCode");
            secretMailTo = ParameterCache.getValue("MpmMailTempCode");
        }
        try {
            // 转成邮件发送消息
            MailMessageEntity mailMessageEntity = new MailMessageEntity();
            mailMessageEntity.setContent("");
            mailMessageEntity.setTitle(emailTitle);
            mailMessageEntity.setMailTo(mailTo);
            // 邮件附件
            mailAttachmentPath = downloadFtpForMail(attachment, attachmentType, tempZipDirectoryName, fileName);
            List<File> fileList = new ArrayList<>();
            File file = new File(mailAttachmentPath);
            fileList.add(file);
            mailMessageEntity.setAttachments(fileList);
            // 发送消息

            int indexOf = mailAttachmentPath.lastIndexOf("\\");
            String temp = mailAttachmentPath.substring(indexOf + 1);
            indexOf = temp.lastIndexOf("/");
            if (indexOf > -1) {
                temp = temp.substring(indexOf + 1);
            }
            sendMail(mailMessageEntity, file, copyMailTo, temp, secretMailTo);
        } finally {
            FileUtil.deleteDirectory(tempZipDirectoryName, true);
        }
    }

    /**
    * @Description:    下载任命书并放在邮件中的附件中
    * @Author:         mengmeng
    * @Date:           2021/8/19 9:55
    * @Version:        1.0
    */
    private String downloadFtpForMail(CboAttachmentEntity attachment, CboAttachmentTypeEntity attachmentType, String directory, String fileName) {
        try {
            FTPProcessor ftpProcessor = null;
            ZipInputStream is = null;
            OutputStream os = null;
            String tempZipFilePath = null;
            String unZipFilePath = null;
            String destDirectory = null;
            try {
                // 临时目录，用于解压缩文件
                File tempZipDirectory = new File(directory);
                if (!tempZipDirectory.exists() && !tempZipDirectory.isDirectory()) {
                    tempZipDirectory.mkdirs();
                }
                // 打开FTP连接,下载并解压
                ftpProcessor = new FTPProcessor();
                ftpProcessor.connect(attachmentType.getFtppath(), attachmentType.getFtpserver(),
                        Integer.parseInt(attachmentType.getFtpport()), attachmentType.getFtpuser(),
                        attachmentType.getFtppwd());
                // Ftp文件路径
                String ftpFilePath = attachment.getSavepath() + attachment.getFilename();
                // Zip文件下载路径，下载Zip文件
                tempZipFilePath = directory + attachment.getFilename();
                ftpProcessor.download(ftpFilePath, tempZipFilePath);
                String displayName = attachment.getDisplayname();
                if (attachmentType.getCompresszip() == 0)// 不压缩
                {
                    unZipFilePath = directory + attachment.getDisplayname();
                } else {
                    // 解压
                    ZipFile zipFile = new ZipFile(tempZipFilePath);
                    zipFile.setFileNameCharset("GBK");
                    if (zipFile.isEncrypted()) {
                        zipFile.setPassword(attachment.getPwd());
                    }
                    List<FileHeader> fileHeaderList = zipFile.getFileHeaders();
                    FileHeader fileHeader = fileHeaderList.get(0);
                    if (fileHeader != null) {
                        unZipFilePath = directory + attachment.getDisplayname();
                        File unZipFile = new File(unZipFilePath);
                        if (fileHeader.isDirectory()) {
                            unZipFile.mkdirs();
                        }
                        is = zipFile.getInputStream(fileHeader);
                        os = new FileOutputStream(unZipFile);
                        int readLen = -1;
                        byte[] buff = new byte[4096];
                        while ((readLen = is.read(buff)) != -1) {
                            os.write(buff, 0, readLen);
                        }
                        UnzipUtil.applyFileAttributes(fileHeader, unZipFile);
                        if (!attachment.getFiletype().equals(".PDF")) {
                            String convertDisplayName = fileName + ".pdf";
                            destDirectory = directory + convertDisplayName;
                            GenerateAppointmentTemplateUtil.convertToPdf(unZipFilePath, destDirectory);
                        }
                    }
                }
            } catch (Exception ex) {
                throw new ServiceException(ex);
            } finally {
                if (os != null) {
                    os.close();
                    os = null;
                }
                if (is != null) {
                    is.close();
                    is = null;
                }
                if (ftpProcessor != null) {
                    ftpProcessor.close();
                }
                FileUtil.deleteFile(tempZipFilePath);
            }
            return attachment.getFiletype().equals(".PDF") ? unZipFilePath : destDirectory;
        } catch (Exception ex) {
            throw new ServiceException(ex);
        }
    }

    /**
     * @Description:    生成任命书描述
     * @Author:         mengmeng
     * @Date:           2021/8/13 20:05
     * @Version:        1.0
     */
    public String getAppointmentDescription(MpmProjectEntity mpmProjectEntity) {
        String decisionUserCode = mpmProjectEntity.getDecisionusercode();
        String dispDecisionUserDeptName = null;
        // 获取决策人员的二级部门
        if (!StringUtil.isEmpty(decisionUserCode)) {
            StringBufferProxy sql = new StringBufferProxy();
            String code = Arrays.stream(decisionUserCode.split(",")).filter(item -> !StringUtil.isEmpty(item)).map(item -> "'" + item + "'").collect(Collectors.joining(","));
            sql.appendSingle(CboUserEntity.FieldCode + " in ({0})", code);
            CboUserService cboUserService = (CboUserService) SpringUtil.getBean("cboUserService");
            List<CboUserEntity> userList = cboUserService.queryByWhere(sql.toString());
            Set<Long> deptIdSet = new HashSet<>();
            String deptIdStr = userList.stream().map(CboUserEntity::getDeptid).filter(item -> {
                if (deptIdSet.contains(item)) {
                    return false;
                }
                else {
                    deptIdSet.add(item);
                    return true;
                }
            }).map(item -> "'" + item + "'").collect(Collectors.joining(","));
            List<CboDeptEntity> deptList = cboDeptService.queryByIds(deptIdStr);
            dispDecisionUserDeptName = deptList.stream().map(CboDeptEntity::getFullname).map(item -> {
                String[] split = item.split("\\\\");
                return split.length > 1 ? split[1] : (split.length > 0 ? split[0] : "");
            }).collect(Collectors.joining("、"));
        }
        String projectName = getProjectName(mpmProjectEntity.getProjectname());
        DatacodeCache datacodeCache = (DatacodeCache) SpringUtil.getBean("datacodeCache");
        String dispProjectLevel = datacodeCache.getValueDynamic("MpmProjectLevel", mpmProjectEntity.getProjectlevel(), "code", "name");
        return projectName + "属于销售项目（项目编号：" + mpmProjectEntity.getProjectcode() + "）, 为实现该项目目标，加强项目的计划、组织、协调、指挥和控制，经公司" + dispDecisionUserDeptName + "共同决策，同意《" + projectName + "》为" + dispProjectLevel + "级销售项目，特成立项目组。";
    }

    /**
     * @Description:    给项目名称后面追加 ‘项目’ 两个字
     * @Author:         mengmeng
     * @Date:           2021/8/13 20:04
     * @Version:        1.0
     */
    private String getProjectName(String projectName) {
        if (StringUtil.isEmpty(projectName)) {
            return "";
        }
        return projectName.endsWith("项目") ? projectName : projectName + "项目";
    }

    /**
     * @Description:    生成任命书
     * @Author:         mengmeng
     * @Date:           2021/8/13 20:04
     * @Version:        1.0
     */
    public void generateAppointment(MpmProjectAppointmentEntity mpmProjectAppointmentEntity, MpmProjectEntity mpmProjectEntity) throws Exception {
        Map<String, Object> param = new HashMap<>();
        param.put("appointmentnumber", mpmProjectAppointmentEntity.getAppointmentnumber());
        String projectName = mpmProjectAppointmentEntity.getProjectname();
        param.put("projectname", getProjectName(projectName));
        param.put("appointmentdescription", mpmProjectAppointmentEntity.getAppointmentdescription());
        param.put("signercode", mpmProjectAppointmentEntity.getSignername());
        param.put("appointmentid", mpmProjectAppointmentEntity.getId());
        // 构造sponsor owner projectmanager列表
        List<Map<String, Object>> sslist = new ArrayList<>();
        generateRole(sslist, "Sponsor", mpmProjectEntity.getSponsor(), mpmProjectEntity.getSponsorcode());
        generateRole(sslist, "Owner", mpmProjectEntity.getOwner(), mpmProjectEntity.getOwnercode());
        generateRole(sslist, "PM", mpmProjectEntity.getProjectmanager(), mpmProjectEntity.getProjectmanagercode());
        String adviser = mpmProjectAppointmentEntity.getAdviser();
        String adviserCode = mpmProjectAppointmentEntity.getAdvisercode();
        if (!StringUtil.isEmpty(adviser) && !StringUtil.isEmpty(adviserCode)) {
            generateRole(sslist, "顾问", adviser, adviserCode);
        }
        param.put("sslist", sslist);
        // 构造核心组
        List<Map<String, Object>> tablelist = new ArrayList<>();
        generateProjectTeam(mpmProjectAppointmentEntity.getId(), tablelist);
        param.put("tablelist", tablelist);
        param.put("projectlevel", mpmProjectEntity.getProjectlevel());

        // 生成任命书
        generateAppointment(param);
    }

    /**
    * @Description:    构造项目组
    * @Author:         mengmeng
    * @Date:           2021/8/19 10:06
    * @Version:        1.0
    */
    private void generateProjectTeam(Long appointId, List<Map<String, Object>> tablelist) {
        List<Map<String, Object>> maps = mpmProjectTeamService.queryTeamAndTeamType(ConvertUtil.convertToString(appointId));
        mpmProjectTeamService.setDispFields(maps);
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle("{0} = '{1}' order by sortcode asc, createon asc", MpmProjectTeamTypeEntity.FieldAppointmentid,
                appointId);
        tablelist.addAll(mpmProjectTeamTypeService.queryMapByWhere(sql.toString()));
        Map<String, List<Map<String, Object>>> teamTypeIdToTeamMap = maps.stream().collect(Collectors.groupingBy(item ->
                ConvertUtil.convertToString(item.get(MpmProjectTeamEntity.FieldTeamid))));
        if (!CollectionUtils.isEmpty(tablelist)) {
            for (Map<String, Object> map : tablelist) {
                map.put("name", map.get(MpmProjectTeamTypeEntity.FieldTeamname));
                String key = ConvertUtil.convertToString(map.get(MpmProjectTeamTypeEntity.FieldId));
                List<Map<String, Object>> temp = teamTypeIdToTeamMap.computeIfAbsent(key, k -> new ArrayList<>());
                map.put("table", temp);
            }
        }
    }

    /**
     * @Description:    构造角色
     * @Author:         mengmeng
     * @Date:           2021/8/13 19:53
     * @Version:        1.0
     */
    private void generateRole(List<Map<String, Object>> sslist, String role, String name, String code) {
        Map<String, Object> sponsor = new HashMap<>();
        sponsor.put("ss", name);
        sponsor.put("ssc", code);
        sponsor.put("ssn", role);
        sslist.add(sponsor);
    }

    /**
     * @Description: 获取项目组成员
     * @Author: mengmeng
     * @Date: 2021/8/17 20:35
     * @Version: 1.0
     */
    private List<String> getStrings(Map<String, Object> appointDoMap, List<MpmProjectTeamEntity> projectTeamDoList) {
        List<String> userCodeList = projectTeamDoList.stream().map(MpmProjectTeamEntity::getUsercode).collect(Collectors.toList());
        userCodeList = userCodeList.stream().filter(item -> !StringUtil.isEmpty(item)).collect(Collectors.toList());
        String projectManagerCode = ConvertUtil.convertToString(appointDoMap.get(MpmProjectAppointmentEntity.FieldProjectmanagercode));
        userCodeList.add(projectManagerCode);
        return userCodeList;
    }

    /**
    * @Description:    填写邮件所需必要信息并发送邮件
    * @Author:         mengmeng
    * @Date:           2021/8/19 9:56
    * @Version:        1.0
    */
    private void sendMail(MailMessageEntity mailMessageEntity, File toFile, String copyMailTo, String toFileName, String secretMailTo) {
        String currentNanoTime = ConvertUtil.convertToString(System.nanoTime());
        String imagePath = System.getProperty("user.dir").replace("bin", "webapps") + "/pdfImage/" + currentNanoTime + "/";
        String imagePrefix = "pdfimage";
        String mailTo = mailMessageEntity.getMailTo();
        /**
         * 邮箱服务器
         */
        String mailServer = ParameterCache.getValue("CboMailServer");
        /**
         * 发送人邮箱账号
         */
        String mailSendUserName = ParameterCache.getValue("CboMailSendUserName");
        /**
         * 发送人邮箱密码
         */
        String mailSendPassword = ParameterCache.getValue("CboMailSendPassword");
        try {
            MimeMessage mimeMessage = setMailServer(mailServer, mailSendUserName, mailSendPassword);
            // 发件人
            String sendername = javax.mail.internet.MimeUtility.encodeText(mailSendUserName);
            mimeMessage.setFrom(new InternetAddress(sendername + "<" + mailSendUserName + ">"));
            // 收件人
            InternetAddress[] arrayRecipients = InternetAddress.parse(mailTo);
            InternetAddress[] copyRecipients = InternetAddress.parse(copyMailTo);
            InternetAddress[] secretRecipients = InternetAddress.parse(secretMailTo);
            mimeMessage.setRecipients(Message.RecipientType.TO, arrayRecipients);
            mimeMessage.setRecipients(Message.RecipientType.CC, copyRecipients);
            // 密送邮件
            mimeMessage.setRecipients(Message.RecipientType.BCC, secretRecipients);
            // 邮件的标题
            String title = mailMessageEntity.getTitle();
            mimeMessage.setSubject(MimeUtility.encodeText(title, "UTF-8", "B"));
            // 邮件图片
            MimeMultipart mimeMultipart = insertImage(toFile, imagePath, imagePrefix);
            // 邮件附件
            MimeMultipart attachPart = new MimeMultipart();
            MimeBodyPart image = new MimeBodyPart();
            image.setContent(mimeMultipart);
            MimeBodyPart attach = new MimeBodyPart();
            DataHandler dataHandler = new DataHandler(new FileDataSource(toFile));
            attach.setDataHandler(dataHandler);
            String property = System.getProperties().getProperty("file.separator");
            // 过滤掉开头的斜线或者下划线
            toFileName = dealFileName(toFileName, property);
            String resultFileName = MimeUtility.encodeText(toFileName, "UTF-8", "B");
            resultFileName = resultFileName.replace("\\r","").replace("\\n","");
            attach.setFileName(resultFileName);
            attachPart.addBodyPart(attach);
            attachPart.addBodyPart(image);
            attachPart.setSubType("mixed");
            // 创建容器描述数据关系
            mimeMessage.setContent(attachPart);
            mimeMessage.saveChanges();
            // 发送邮件
            Transport.send(mimeMessage);
        }
        catch (SendFailedException s) {
            // 判断当前失败信息，如果为地址错误，则过滤无效地址后重发
            if (INVALID_ADDRESS_MESSAGE.equals(s.getMessage())) {
                Address[] addresses = s.getInvalidAddresses();
                List<String> addressList = new ArrayList<>();

                List<String> recipientList = Arrays.stream(mailTo.split(",")).collect(Collectors.toList());
                List<String> ccList = Arrays.stream(copyMailTo.split(",")).collect(Collectors.toList());
                for (Address address : addresses) {
                    InternetAddress internetAddress = (InternetAddress) address;
                    String invalidAddress = internetAddress.getAddress();
                    if (recipientList.contains(invalidAddress)) {
                        recipientList.remove(invalidAddress);
                    }
                    if (ccList.contains(invalidAddress)) {
                        ccList.remove(invalidAddress);
                    }
                    addressList.add(invalidAddress);
                }
                logger.info("存在不可用邮箱地址:{},过滤后重新发送邮件...", JSON.toJSONString(addressList));

                if (CollectionUtils.isEmpty(recipientList)) {
                    logger.info("收件人不存在有效的邮箱地址,已配置但无效的邮箱地址：{}", JSON.toJSONString(recipientList));
                    throw new ServiceException("不存在有效的邮箱地址，已配置但无效的邮箱地址：" + JSON.toJSONString(addressList));
                }
                if (CollectionUtils.isEmpty(ccList)) {
                    logger.info("抄送人不存在有效的邮箱地址,已配置但无效的邮箱地址：{}", JSON.toJSONString(ccList));
                    throw new ServiceException("不存在有效的邮箱地址，已配置但无效的邮箱地址：" + JSON.toJSONString(addressList));
                }
                // 重新发送
                mailMessageEntity.setMailTo(recipientList.stream().collect(Collectors.joining(",")));
                copyMailTo = ccList.stream().collect(Collectors.joining(","));
                sendMail1(mailMessageEntity, toFile, copyMailTo, toFileName);
            } else {
                throw new ServiceException(s);
            }
        }
        catch (Exception ex) {
            throw new BusinessException(ex);
        } finally {
            FileUtil.deleteDirectory(imagePath, true);
        }
    }

    /**
    * @Description:    在发送给失效的邮箱时，需要重新发送邮件，重写发送邮件的方法，避免进入递归死循环
    * @Author:         mengmeng
    * @Date:           2021/10/19 10:52
    * @Version:        1.0
    */
    private void sendMail1(MailMessageEntity mailMessageEntity, File toFile, String copyMailTo, String toFileName) {
        String currentNanoTime = ConvertUtil.convertToString(System.nanoTime());
        String imagePath = System.getProperty("user.dir").replace("bin", "webapps") + "/pdfImage/" + currentNanoTime + "/";
        String imagePrefix = "pdfimage";
        String mailTo = mailMessageEntity.getMailTo();
        /**
         * 邮箱服务器
         */
        String mailServer = ParameterCache.getValue("CboMailServer");
        /**
         * 发送人邮箱账号
         */
        String mailSendUserName = ParameterCache.getValue("CboMailSendUserName");
        /**
         * 发送人邮箱密码
         */
        String mailSendPassword = ParameterCache.getValue("CboMailSendPassword");
        try {
            MimeMessage mimeMessage = setMailServer(mailServer, mailSendUserName, mailSendPassword);
            // 发件人
            String sendername = javax.mail.internet.MimeUtility.encodeText(mailSendUserName);
            mimeMessage.setFrom(new InternetAddress(sendername + "<" + mailSendUserName + ">"));
            // 收件人
            InternetAddress[] arrayRecipients = InternetAddress.parse(mailTo);
            InternetAddress[] copyRecipients = InternetAddress.parse(copyMailTo);
            mimeMessage.setRecipients(Message.RecipientType.TO, arrayRecipients);
            mimeMessage.setRecipients(Message.RecipientType.CC, copyRecipients);
            // 邮件的标题
            String title = mailMessageEntity.getTitle();
            mimeMessage.setSubject(MimeUtility.encodeText(title, "UTF-8", "B"));
            // 邮件图片
            MimeMultipart mimeMultipart = insertImage(toFile, imagePath, imagePrefix);
            // 邮件附件
            MimeMultipart attachPart = new MimeMultipart();
            MimeBodyPart image = new MimeBodyPart();
            image.setContent(mimeMultipart);
            MimeBodyPart attach = new MimeBodyPart();
            DataHandler dataHandler = new DataHandler(new FileDataSource(toFile));
            attach.setDataHandler(dataHandler);
            String property = System.getProperties().getProperty("file.separator");
            // 过滤掉开头的斜线或者下划线
            toFileName = dealFileName(toFileName, property);
            String resultFileName = MimeUtility.encodeText(toFileName, "UTF-8", "B");
            resultFileName = resultFileName.replace("\\r","").replace("\\n","");
            attach.setFileName(resultFileName);
            attachPart.addBodyPart(attach);
            attachPart.addBodyPart(image);
            attachPart.setSubType("mixed");
            // 创建容器描述数据关系
            mimeMessage.setContent(attachPart);
            mimeMessage.saveChanges();
            // 发送邮件
            Transport.send(mimeMessage);
        } catch (Exception ex) {
            throw new BusinessException(ex);
        } finally {
            FileUtil.deleteDirectory(imagePath, true);
        }
    }

    /**
    * @Description:    设置邮箱服务
    * @Author:         mengmeng
    * @Date:           2021/10/19 10:46
    * @Version:        1.0
    */
    private MimeMessage setMailServer(String mailServer, String mailSendUserName, String mailSendPassword) throws GeneralSecurityException {
        // 邮件服务器
        Properties prop = System.getProperties();
        prop.setProperty("mail.host", mailServer);
        prop.setProperty("mail.transport.protocol", "smtp");
        prop.setProperty("mail.smtp.auth", "true");
        prop.setProperty("mail.smtp.port", "465");
        prop.setProperty("mail.smtp.ssl.enable", "true");
        System.getProperties().setProperty("mail.mime.splitlongparameters", "false");
        // 设置SSL加密
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        prop.put("mail.smtp.ssl.socketFactory", sf);
        // 创建会话对象
        Authenticator authenticator = new Authenticator() {
            @Override
            public PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(mailSendUserName, mailSendPassword);
            }
        };
        Session session = Session.getInstance(prop, authenticator);
        session.setDebug(true);
        // MimeMessage对象
        return new MimeMessage(session);
    }

    private String dealFileName(String fileName, String property) {
        if (fileName.startsWith(property)) {
            fileName = fileName.substring(1);
        }
        else {
            return fileName;
        }
        return dealFileName(fileName, property);
    }

    /**
    * @Description:    向邮件内容中填写图片
    * @Author:         mengmeng
    * @Date:           2021/8/19 9:57
    * @Version:        1.0
    */
    private MimeMultipart insertImage(File pdf, String imagePath, String imageNamePrefix) throws MessagingException, IOException {
        MimeMultipart mimeMultipart = new MimeMultipart();
        int total = PdfToImageUtil.toImageFromByte(imagePath, imageNamePrefix, FileUtil.convertFileToBytes(pdf), true);
//        MimeBodyPart image = new MimeBodyPart();
//        //图片需要经过数据处理..DataHandler：数据处理
//        image.setDataHandler(new DataHandler(new FileDataSource(imagePath + imageNamePrefix + ".png")));//在我们的body中放入这个处理的图片数据
//        image.setContentID(imageNamePrefix + ".png");//给图片设置一个ID方便调用
//        mimeMultipart.addBodyPart(image);
        MimeBodyPart mailContent = new MimeBodyPart();
        String content = "<hr color='#b5c4df' style='width:200px;float:left;'><br>\n" +
                "<span style='color: rgb(128, 128, 128);line-height: 18px;font-family: Verdana;white-space: nowrap;font-size: 12px;'>&nbsp;&nbsp;鼎信通讯 经营管理部</span><br>\n" +
                "<span style='font-family: Calibri;color: rgb(128, 128, 128);white-space: nowrap;line-height: normal;font-size: 12px;'>&nbsp;&nbsp;=========================================</span><br>\n" +
                "<span style='color: rgb(128, 128, 128);line-height: 18px;font-family: Verdana;white-space: nowrap;font-size: 12px;'>&nbsp;&nbsp;青岛市高新区华贯路858号 鼎信科技产业园</span>";
        mailContent.setContent(content, "text/html;charset=UTF-8");
        mimeMultipart.addBodyPart(mailContent);
        mimeMultipart.setSubType("related");
        return mimeMultipart;
    }

    /**
    * @Description:    下载文件后转ftp
    * @Author:         mengmeng
    * @Date:           2021/8/19 9:57
    * @Version:        1.0
    */
    private void downloadFtp(Map<String, Object> resultMap, Map<String, Object> paraMap, CboAttachmentEntity attachment,
                             CboAttachmentTypeEntity attachmentType) {
        try {
            FTPProcessor ftpProcessor = null;
            ZipInputStream is = null;
            OutputStream os = null;
            String tempZipFilePath = null;
            String unZipFilePath = null;
            String tempZipDirectoryName = null;
            String uuid = UUID.randomUUID().toString();
            String property = System.getProperties().getProperty("file.separator");
            try {
                // 临时目录，用于解压缩文件
                tempZipDirectoryName = BaseUtil.getProjectPath() + "zip" + property + uuid;
                File tempZipDirectory = new File(tempZipDirectoryName);
                if (!tempZipDirectory.exists() && !tempZipDirectory.isDirectory()) {
                    tempZipDirectory.mkdirs();
                }
                // 打开FTP连接,下载并解压
                ftpProcessor = new FTPProcessor();
                ftpProcessor.connect(attachmentType.getFtppath(), attachmentType.getFtpserver(),
                        Integer.parseInt(attachmentType.getFtpport()), attachmentType.getFtpuser(),
                        attachmentType.getFtppwd());
                // Ftp文件路径
                String ftpFilePath = attachment.getSavepath() + attachment.getFilename();
                // Zip文件下载路径，下载Zip文件
                tempZipFilePath = tempZipDirectoryName + property + attachment.getFilename();
                ftpProcessor.download(ftpFilePath, tempZipFilePath);
                String displayName = attachment.getDisplayname();
                if (attachmentType.getCompresszip() == 0)// 不压缩
                {
                    resultMap.put("attFileName", displayName);
                    resultMap.put("attInputStream", FileUtil.convertFileToBytes(tempZipFilePath));
                } else {
                    // 解压
                    ZipFile zipFile = new ZipFile(tempZipFilePath);
                    zipFile.setFileNameCharset("GBK");
                    if (zipFile.isEncrypted()) {
                        zipFile.setPassword(attachment.getPwd());
                    }
                    List<FileHeader> fileHeaderList = zipFile.getFileHeaders();
                    FileHeader fileHeader = fileHeaderList.get(0);
                    if (fileHeader != null) {
                        unZipFilePath = tempZipDirectoryName + property + displayName;
                        File unZipFile = new File(unZipFilePath);
                        if (fileHeader.isDirectory()) {
                            unZipFile.mkdirs();
                        }
                        is = zipFile.getInputStream(fileHeader);
                        os = new FileOutputStream(unZipFile);
                        int readLen = -1;
                        byte[] buff = new byte[4096];
                        while ((readLen = is.read(buff)) != -1) {
                            os.write(buff, 0, readLen);
                        }
                        UnzipUtil.applyFileAttributes(fileHeader, unZipFile);
                        String convertDisplayName = displayName.substring(0, displayName.indexOf(".")) + ".pdf";
                        String destDirectory = tempZipDirectoryName + property + convertDisplayName;
                        GenerateAppointmentTemplateUtil.convertToPdf(unZipFilePath, destDirectory);
                        resultMap.put("attFileName", convertDisplayName);
                        resultMap.put("attInputStream", FileUtil.convertFileToBytes(destDirectory));
                    }
                }
            } catch (Exception ex) {
                throw new ServiceException(ex);
            } finally {
                if (os != null) {
                    os.close();
                    os = null;
                }
                if (is != null) {
                    is.close();
                    is = null;
                }
                if (ftpProcessor != null) {
                    ftpProcessor.close();
                }
                // 删除压缩文件
                FileUtil.deleteFile(tempZipFilePath);
                if (ParameterCache.getBooleanValue("CboAttchmentUnZipDelete", true)) {
                    // 删除解压后的文件
                    if (unZipFilePath != null) {
                        FileUtil.deleteFile(unZipFilePath);
                    }
                    // 删除临时目录
                    FileUtil.deleteDirectory(tempZipDirectoryName, true);
                } else {
                    // edit by jichanghong 20180719
                    // 电子工艺文件管理系统，根据工序拆分pdf文件要用unZipFilePath 与
                    // tempZipDirectoryName
                    resultMap.put("unZipFilePath", unZipFilePath);
                    resultMap.put("tempZipDirectoryName", tempZipDirectoryName);
                }
            }
        } catch (Exception ex) {
            throw new ServiceException(ex);
        }
    }

    /**
    * @Description:    现在任命书模板
    * @Author:         mengmeng
    * @Date:           2021/8/19 9:58
    * @Version:        1.0
    */
    private void downloadTemplate(String disAddr, Boolean ifBLevel, Boolean ifCLevel) {
        List<CboAttachmentTypeEntity> cboAttachmentTypeEntities = cboAttachmentTypeService.queryByWhere(" sourcetype = 'MpmProjectAppointmentTemplate' ");
        if (CollectionUtils.isEmpty(cboAttachmentTypeEntities)) {
            throw new ServiceException("未配置任命书模板附件类型！！！");
        }
        CboAttachmentTypeEntity attachmentType = cboAttachmentTypeEntities.get(0);
        String property = System.getProperties().getProperty("file.separator");

        FTPProcessor ftpProcessor = null;
        try {
            // 打开FTP连接,下载并解压
            ftpProcessor = new FTPProcessor();
            ftpProcessor.connect(attachmentType.getFtppath(), attachmentType.getFtpserver(),
                    Integer.parseInt(attachmentType.getFtpport()), attachmentType.getFtpuser(),
                    attachmentType.getFtppwd());
            // Ftp文件路径 B级项目加新模版
            String ftpFilePath = ifBLevel ? "2.docx":"1.docx";
            if (ifCLevel) {
                ftpFilePath = "2.docx";
            }
            // Zip文件下载路径，下载Zip文件
            String tempZipFilePath = disAddr + property + "项目任命书模板.docx";
            ftpProcessor.download(ftpFilePath, tempZipFilePath);
        } catch (Exception ex) {
            throw new ServiceException(ex);
        } finally {
            if (ftpProcessor != null) {
                try {
                    ftpProcessor.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
    * @Description:    上传任命书附件
    * @Author:         mengmeng
    * @Date:           2021/8/19 9:58
    * @Version:        1.0
    */
    private void uploadAppointment(String sourceId, File file) {
        Map<String, Object> param = new HashMap<>();
        param.put("sourceType", "MpmProjectAppointmentGenerate");
        param.put("sourceId", sourceId);
        param.put("description", "SystemUpload");
        cboAttachmentService.executeUpload(param, file);
    }

    /**
    * @Description:    删除系统生成的任命书
    * @Author:         mengmeng
    * @Date:           2021/8/19 9:59
    * @Version:        1.0
    */
    private void deleteAppointment(String sourceId) {
        cboAttachmentService.deleteByWhere(" sourcetype = 'MpmProjectAppointmentGenerate' and sourceid = " + sourceId);
    }

    /**
     * @author: zhangsui
     * @date: 2016年8月8日下午2:26:58
     * @param billEntity
     * @param nodeIns
     * @return_type: void
     * @description: 审批后处理
     * @modify:
     */
    @Override
    protected void afterApprove(TapEntity billEntity, CboApprovalNodeInsEntity nodeIns, CboApprovalNodeEntity node,
                                SessionUserBean sessionUserBean) {
        super.afterApprove(billEntity, nodeIns, node, sessionUserBean);
    }
    /**
     * @author houyuhang
     * @Description 首页信息概览任命超期
     * @Date 2021/11/29
     * @return Map<String,Object>
     **/
    @Override
    public Map<String,Object> queryOverdueAppointment(Map<String,Object> paraMap){
        Map<String, Object> overdueAppointmentResult = new HashMap<>();
        StringBufferProxy sql = new StringBufferProxy();
        // 项目状态为进行中的数据权限内项目
        sql.appendSingle(" MpmProject.projectstate= '{0}' and MpmProject.enabled = 1 " +
                " and {1} ",MpmSystemConst.ExecuteStateCode,
                mpmProjectService.whereExistsSqlForIndex(MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode
                        , ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
        // 任命超期拼接字符串，项目立项完成时间不为空，但项目任命不存在或者只存在一条未审批完成的任命
        sql.appendSingle(" AND MPMPROJECT.FINISHDATE IS NOT NULL AND (MPMPROJECTAPPOINTMENT.ID IS NULL OR (MPMPROJECTAPPOINTMENT.STATE < 9 " +
                " AND NOT EXISTS( SELECT ID FROM MPMPROJECTAPPOINTMENT MPMAPP WHERE MPMAPP.PROJECTCODE = MPMPROJECTAPPOINTMENT.PROJECTCODE" +
                " AND MPMAPP.ID != MPMPROJECTAPPOINTMENT.ID)))");
        // 获取4天之前的日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        String overdueAppointmentTime = MpmSystemConst.overdueAppointmentTime;
        int time = Integer.parseInt(overdueAppointmentTime) * (-1);
        calendar.add(Calendar.DATE,time);
        Date overdueDate = calendar.getTime();
        String overdueTime = DateUtil.dateToString(overdueDate,"yyyy-MM-dd");
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("whereSql",sql.toString());
        dataMap.put("overdue",1);
        dataMap.put("overduetime",overdueTime);
        int countAppointment = mpmProjectService.getCount(dataMap,"queryAppointmentOverdue");
        overdueAppointmentResult.put("code", "overdueAppointmentNum");
        overdueAppointmentResult.put("name", "超期任命");
        overdueAppointmentResult.put("iconImg", "/static/images/paojectManager/overdueAppointment.png");
        overdueAppointmentResult.put("value", countAppointment);
        return overdueAppointmentResult;
    }
    /**
     * @author houyuhang
     * @Description 首页信息概览任命待办
     * @Date 2021/11/29
     * @return Map<String,Object>
     **/
    @Override
    public Map<String,Object> queryBacklogAppointment(Map<String,Object> paraMap) {
        Map<String, Object> backlogAppointmentResult = new HashMap<>();
        StringBufferProxy sql = new StringBufferProxy();
        // 项目状态为进行中的数据权限内项目
        sql.appendSingle(" MpmProject.projectstate= '{0}' and MpmProject.enabled = 1 and {1} ",MpmSystemConst.ExecuteStateCode,
                mpmProjectService.whereExistsSqlForIndex(MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode,
                        ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
        // 任命待办拼接字符串，项目立项完成时间不为空，但项目任命不存在或者只存在一条未提交审批的任命
        sql.appendSingle(" AND MPMPROJECT.FINISHDATE IS NOT NULL AND (MPMPROJECTAPPOINTMENT.ID IS NULL OR (MPMPROJECTAPPOINTMENT.STATE = 0 " +
                " AND NOT EXISTS( SELECT ID FROM MPMPROJECTAPPOINTMENT MPMAPP WHERE MPMAPP.PROJECTCODE = MPMPROJECTAPPOINTMENT.PROJECTCODE" +
                " AND MPMAPP.ID != MPMPROJECTAPPOINTMENT.ID)))");
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("whereSql",sql.toString());
        int countBacklogAppointment = mpmProjectService.getCount(dataMap,"queryAppointmentOverdue");
        backlogAppointmentResult.put("code", "backlogAppointmentNum");
        backlogAppointmentResult.put("name", "任命待办");
        backlogAppointmentResult.put("iconImg", "/static/images/paojectManager/backlogappointment.png");
        backlogAppointmentResult.put("value", countBacklogAppointment);
        return backlogAppointmentResult;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    protected void deleteBefore(String whereSql) {
        super.deleteBefore(whereSql);
        //找到这条任命
        List<MpmProjectAppointmentEntity> mpmProjectAppointmentEntities = this.queryByWhere(whereSql);
        if (mpmProjectAppointmentEntities.size() == 0) {
            return;
        }
        // 获取任命书的id
        String appointmentid = ConvertUtil.convertToString(mpmProjectAppointmentEntities.get(0).getId());
        // 删除对应的任命组信息
        StringBufferProxy delsql = new StringBufferProxy();
        delsql.appendSingle("appointmentid = '{0}' ", appointmentid);
        mpmProjectTeamTypeService.deleteByWhere(delsql.toString());
        //删除对应的任命成员信息
        mpmProjectTeamService.deleteByWhere(delsql.toString());
    }
    /**
     * @author houyuhang
     * @Description 客户为省级且采购模式为招标的A级项目
     * @Date 2021/07/13
     * @return Map<String,Object>
     **/
    public boolean isGenGroup(String projectcode) {
        StringBufferProxy sql = new StringBufferProxy();
        String purchasePattern = MpmSystemConst.PurchasePattern.chanpinBid + "," + MpmSystemConst.PurchasePattern.fuwuBid + "," + MpmSystemConst.PurchasePattern.dianshang;
        String projectLevel = MpmSystemConst.ProjectLevel.A + "," + MpmSystemConst.ProjectLevel.B;
        sql.appendSingle(" projectcode = '{0}' and clientlevel like '%{1}%' and {2} in ({3}) and projectlevel in ({4}) ",
                projectcode, MpmSystemConst.ClientLevel.Province, MpmProjectSaleEntity.FieldPurchasepattern, purchasePattern, projectLevel);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("whereSql",sql.toString());
        int count = mpmProjectService.getCount(dataMap,"projectALevel");
        return count > 0;
    }
    /***
     * @description: 任命变更审批时保存basechangelog表内容
     * @return
     * @author: houyuhang
     * @date: 2023/02/06
     * @modify:
     */
    public void approvalSaveAppointmentLog(MpmProjectAppointmentEntity mpmProjectAppointmentEntity) throws Exception {
        // 删除上次的basechangelog
        baseChangeLogService.deleteByWhere(" topsourcetype='"+mpmProjectAppointmentEntity.getTableName()+"'"
                + " and topsourceid='"+mpmProjectAppointmentEntity.getId()+"'");
        // 保存basechangelog信息
        this.getBaseAppointmentEntity(mpmProjectAppointmentEntity.convertToMap());
    }
    /***
     * @description: 获取变更具体内容
     * @return
     * @author: houyuhang
     * @date: 2023/02/03
     * @modify:
     */
    public void getBaseAppointmentEntity(Map<String, Object> inputMap) throws Exception {
        // 获取变更前一个任命信息
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" projectcode = '{0}' and state = 9 order by createon desc ", inputMap.get("projectcode"));
        List<Map<String, Object>> appList = this.queryMapByWhere(sql.toString());
        if (CollectionUtil.isEmpty(appList)) {
            return;
        }
        // 获取变更version记录
        int version = appList.size() + 1;
        Map<String, Object> oldMap = appList.get(0);
        // 拼接比对字段
        Map<String, Object> changeMap = new HashMap<String, Object>();
        changeMap.put("topsourcetype",MpmProjectAppointmentEntity.tableName);
        changeMap.put("topsourceid", ConvertUtil.convertToString(inputMap.get("id")));
        changeMap.put("sourcetype", MpmProjectAppointmentEntity.tableName);
        changeMap.put("sourceid", ConvertUtil.convertToString(inputMap.get("id")));
        changeMap.put("newmap", inputMap);
        changeMap.put("oldmap", oldMap);
        changeMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Edit);
        changeMap.put("version", version);
        Map<String, Object> changeResMap = this.getMainChangeLogEntity(changeMap);
        if (changeResMap != null) {
            baseChangeLogService.insertLogMap(changeResMap);
        }
        // 获取之前版本和当前版本的团队类别
        List<Map<String, Object>> oldTeamTypeList = mpmProjectTeamTypeService.queryMapByWhere(" appointmentid=" + oldMap.get("id"));
        List<Map<String, Object>> newTeamTypeList = mpmProjectTeamTypeService.queryMapByWhere(" appointmentid=" + inputMap.get("id"));
        this.saveGeneralChangeEntity(newTeamTypeList, oldTeamTypeList, inputMap, version, MpmProjectTeamTypeEntity.tableName, MpmProjectAppointmentEntity.tableName);
        // 获取之前版本和当前版本的项目组成员
        List<Map<String, Object>> oldTeamList = mpmProjectTeamService.queryMapByWhere(" appointmentid=" + oldMap.get("id"));
        List<Map<String, Object>> newTeamList = mpmProjectTeamService.queryMapByWhere(" appointmentid=" + inputMap.get("id"));
        this.saveGeneralChangeEntity(newTeamList, oldTeamList, inputMap, version, MpmProjectTeamEntity.tableName, MpmProjectAppointmentEntity.tableName);
    }
    /***
     * @description: 保存子表变更信息通用方法
     * @return
     * @author: houyuhang
     * @date: 2023/02/06
     * @modify:
     */
    public void saveGeneralChangeEntity(List<Map<String, Object>> teamTypeList, List<Map<String, Object>> teamTypeHistoryList,
                                         Map<String, Object> inputMap, int version, String sourcetype, String topsourcetype) throws Exception {
        Map<String, Object> changeProductMap = new HashMap<String, Object>();
        changeProductMap.put("sourcetype", sourcetype);
        changeProductMap.put("topsourcetype", topsourcetype);
        changeProductMap.put("topsourceid", ConvertUtil.convertToString(inputMap.get("id")));
        changeProductMap.put("version", version);
        List<String> noDelIds = new ArrayList<String>();
        for (Map<String, Object> newItem : teamTypeList) {
            if (newItem.containsKey("copysourceid") && !"0".equals(newItem.get("copysourceid").toString())) {
                boolean hasHistory = false;
                Map<String, Object> matchHistory = new HashMap<String, Object>();
                for (Map<String, Object> historyItem : teamTypeHistoryList) {
                    if (newItem.get("copysourceid").toString().equals(historyItem.get("id").toString())) {
                        hasHistory = true;
                        matchHistory = historyItem;
                    }
                }
                if (hasHistory) {
                    noDelIds.add(ConvertUtil.convertToString(matchHistory.get("id")));
                    changeProductMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Edit);
                    changeProductMap.put("newmap", newItem);
                    changeProductMap.put("oldmap", matchHistory);
                    changeProductMap.put("sourceid", newItem.get("id"));
                    Map<String, Object> perContent = this.getMainChangeLogEntity(changeProductMap);
                    if(perContent != null){
                        baseChangeLogService.insertLogMap(perContent);
                    }
                }
            } else {
                changeProductMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Add);
                changeProductMap.put("newmap", newItem);
                changeProductMap.put("oldmap", newItem);
                changeProductMap.put("sourceid", newItem.get("id"));
                baseChangeLogService.insertLogMap(this.getMainChangeLogEntity(changeProductMap));
            }
        }
        // 删除
        if(noDelIds.size()>0) {
            String lowerFirst = Character.toLowerCase(sourcetype.charAt(0)) + sourcetype.substring(1);
            String serviceName = lowerFirst + "Service";
            TapService serviceBean = (TapService) SpringUtil.getBean(serviceName);
            List<Map<String,Object>> delProducts = serviceBean.queryMapByWhere( " appointmentid =" + teamTypeHistoryList.get(0).get("appointmentid") + " and id not in (" + StringUtils.join(noDelIds, ",") + ")");
            for(Map<String,Object> delItem : delProducts){
                changeProductMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Del);
                changeProductMap.put("newmap", delItem);
                changeProductMap.put("oldmap", delItem);
                changeProductMap.put("sourceid", delItem.get("id"));
                baseChangeLogService.insertLogMap(this.getMainChangeLogEntity(changeProductMap));
            }
        }
    }
}
